/**
 * 
 */
package org.xyz.util;

import java.io.File;
import java.io.IOException;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;

/**
 * 声音工具类:播放声音文件
 * 
 * @author dai.rui.lin
 * 
 */
public final class AudioHelper implements OnCompletionListener, OnErrorListener {

	private static AudioHelper mInstance = null;

	public static AudioHelper getInstance(Context context) {
		if (mInstance == null) {
			mInstance = new AudioHelper(context);
		}
		return mInstance;
	}

	private Context mContext;
	AudioManager audioManager;

	AudioHelper(Context context) {
		mContext = context;
		audioManager = (AudioManager) mContext
				.getSystemService(Context.AUDIO_SERVICE);
	}

	static final String SAMPLE_PREFIX = "recording";
	static final String SAMPLE_PATH_KEY = "sample_path";
	static final String SAMPLE_LENGTH_KEY = "sample_length";

	public static final int IDLE_STATE = 0;
	public static final int RECORDING_STATE = 1;
	public static final int PLAYING_STATE = 2;

	int mState = IDLE_STATE;

	public static final int NO_ERROR = 0;
	public static final int SDCARD_ACCESS_ERROR = 1;
	public static final int INTERNAL_ERROR = 2;
	public static final int IN_CALL_RECORD_ERROR = 3;

	public interface OnStateChangedListener {
		public void onStateChanged(int state);

		public void onError(int error);
	}

	OnStateChangedListener mOnStateChangedListener = null;
	long mSampleStart = 0; // time at which latest record or play operation
							// started
	int mSampleLength = 0; // length of current sample
	File mSampleFile = null;
	MediaPlayer mPlayer = null;

	public void restoreState(Bundle recorderState) {
		String samplePath = recorderState.getString(SAMPLE_PATH_KEY);
		if (samplePath == null)
			return;
		int sampleLength = recorderState.getInt(SAMPLE_LENGTH_KEY, -1);
		if (sampleLength == -1)
			return;

		File file = new File(samplePath);
		if (!file.exists())
			return;
		if (mSampleFile != null
				&& mSampleFile.getAbsolutePath().compareTo(
						file.getAbsolutePath()) == 0)
			return;
		delete();
		mSampleFile = file;
		mSampleLength = sampleLength;

		signalStateChanged(IDLE_STATE);
	}

	public void setOnStateChangedListener(OnStateChangedListener listener) {
		mOnStateChangedListener = listener;
	}

	public int state() {
		return mState;
	}

	public int progress() {
		if (mState == RECORDING_STATE || mState == PLAYING_STATE)
			return (int) ((System.currentTimeMillis() - mSampleStart) / 1000);
		return 0;
	}

	public int sampleLength() {
		return mSampleLength;
	}

	public File sampleFile() {
		return mSampleFile;
	}

	public void delete() {
		stop();

		if (mSampleFile != null)
			mSampleFile.delete();

		mSampleFile = null;
		mSampleLength = 0;

		signalStateChanged(IDLE_STATE);
	}

	public void clear() {
		stop();
		mSampleLength = 0;
		signalStateChanged(IDLE_STATE);
	}

	public boolean isPlaying() {
		if (mPlayer == null || !mPlayer.isPlaying()) {
			return false;
		} else {
			return true;
		}
	}

	public void startPlayback(String file) {
		stop();
		mPlayer = new MediaPlayer();
		try {
			// mPlayer.setVolume(5.0F, 5.0F);
			mPlayer.setDataSource(new File(file).getAbsolutePath());
			mPlayer.setOnCompletionListener(this);
			// mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mPlayer.setOnErrorListener(this);
			mPlayer.prepare();
			mPlayer.start();

		} catch (IllegalArgumentException e) {
			setError(INTERNAL_ERROR);
			mPlayer = null;
			return;
		} catch (IOException e) {
			setError(SDCARD_ACCESS_ERROR);
			mPlayer = null;
			return;
		}

		mSampleStart = System.currentTimeMillis();
		setState(PLAYING_STATE);
	}

	public void startPlayback(Uri mUri) {
		stop();
		mPlayer = MediaPlayer.create(mContext, mUri);
		try {
			// mPlayer.setVolume(5.0F, 5.0F);
			mPlayer.setOnCompletionListener(this);
			// mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
			mPlayer.setOnErrorListener(this);
			mPlayer.prepare();
			mPlayer.start();

		} catch (IllegalArgumentException e) {
			setError(INTERNAL_ERROR);
			mPlayer = null;
			return;
		} catch (IOException e) {
			setError(SDCARD_ACCESS_ERROR);
			mPlayer = null;
			return;
		}

		mSampleStart = System.currentTimeMillis();
		setState(PLAYING_STATE);
	}

	public void startPlayback(int resId) {
		stop();
		mPlayer = MediaPlayer.create(mContext, resId);
		try {
			mPlayer.setOnCompletionListener(this);
			mPlayer.setOnErrorListener(this);
			mPlayer.start();

		} catch (IllegalArgumentException e) {
			setError(INTERNAL_ERROR);
			mPlayer = null;
			return;
		}

		mSampleStart = System.currentTimeMillis();
		setState(PLAYING_STATE);
	}

	public void startSystemNotification(final Context context) {
		onPlayRingtone(context);
	}

	private Ringtone mDefaultRingtone = null;

	/**
	 * @param context
	 */
	private void onPlayRingtone(final Context context) {

		if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) {
			mDefaultRingtone.stop();
			mDefaultRingtone = null;
		}

		Uri mUriForDefaultItem = RingtoneManager
				.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		Ringtone mRingtone = RingtoneManager.getRingtone(context,
				mUriForDefaultItem);
		if (mRingtone != null) {
			mRingtone.play();
		}
		mDefaultRingtone = mRingtone;
	}

	/**
	 * 把模式调成听筒放音模式
	 */
	void setAudioModeInCall() {

		int mode = audioManager.getMode();
		if (mode != AudioManager.MODE_IN_CALL) {
			audioManager.setMode(AudioManager.MODE_IN_CALL);// 把模式调成听筒放音模式
		}
	}

	/**
	 * 播放声音
	 * 
	 * @param isCall
	 *            是否是听筒模式播放声音
	 */
	public void startPlayback(boolean isCall) {
		stop();

		mPlayer = new MediaPlayer();
		try {
			if (isCall) {
				setAudioModeInCall();
			}

			mPlayer.setDataSource(mSampleFile.getAbsolutePath());
			mPlayer.setOnCompletionListener(this);
			mPlayer.setOnErrorListener(this);
			mPlayer.prepare();
			mPlayer.start();

		} catch (IllegalArgumentException e) {
			setError(INTERNAL_ERROR);
			mPlayer = null;
			return;
		} catch (IOException e) {
			setError(SDCARD_ACCESS_ERROR);
			mPlayer = null;
			return;
		}

		mSampleStart = System.currentTimeMillis();
		setState(PLAYING_STATE);
	}

	public void stopPlayback() {
		if (mPlayer == null) // we were not in playback
			return;

		if (mPlayer.isPlaying()) {
			mPlayer.stop();
		}
		mPlayer.release();
		mPlayer = null;
		setState(IDLE_STATE);
	}

	public void stop() {
		stopPlayback();
	}

	public boolean onError(MediaPlayer mp, int what, int extra) {
		stop();
		setError(SDCARD_ACCESS_ERROR);
		return true;
	}

	public void onCompletion(MediaPlayer mp) {
		stop();
	}

	private void setState(int state) {
		if (state == mState)
			return;

		mState = state;
		signalStateChanged(mState);
	}

	private void signalStateChanged(int state) {
		if (mOnStateChangedListener != null)
			mOnStateChangedListener.onStateChanged(state);
	}

	private void setError(int error) {
		if (mPlayer != null) {
			mPlayer.reset();
		}
		if (mOnStateChangedListener != null)
			mOnStateChangedListener.onError(error);
	}

}
